﻿// <copyright file="TypeConverter.cs" company="Signal Processing Lab, Wuhan University">
// Copyright (c) 2009-2010 All Right Reserved
// </copyright>
// <author>Xinping Deng</author>
// <email>dentoby@gmail.com</email>
// <date>2010-4</date>
// <summary>This is part of Image.NET project.</summary>

namespace SPLWHU.Core.Raster
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;

    /// <summary>
    /// To convert the the value, or array, or <see cref="Matrix&lt;T&gt;"/> of a specified type to the value of another type.
    /// </summary>
    public class TypeConverter
    {
        /// <summary>
        /// The created <see cref="DynamicCode"/>.
        /// </summary>
        private static Dictionary<string, DynamicCode> dynamicCodeHash = new Dictionary<string, DynamicCode>();

        /// <summary>
        /// Gets the specified <see cref="DynamicCode"/>.
        /// </summary>
        /// <param name="hashString">The hash string.</param>
        /// <returns>The dynamic code.</returns>
        public static DynamicCode Hash(string hashString)
        {
            if (!dynamicCodeHash.ContainsKey(hashString))
            {
                return null;
            }

            return dynamicCodeHash[hashString];
        }

        /// <summary>
        /// Converts data of the specified type to another type.
        /// </summary>
        /// <typeparam name="TInput">The type of the input.</typeparam>
        /// <typeparam name="TOutput">The type of the output.</typeparam>
        /// <param name="input">The input data.</param>
        /// <returns>The converted data.</returns>
        public static TOutput Convert<TInput, TOutput>(TInput input)
        {
            // Gets the corresponding dynamic code.
            string tin = typeof(TInput).ToString();
            string tout = typeof(TOutput).ToString();
            string hashString = "ConvertValue.<" + tin + ">.<" + tout + ">";
            DynamicCode dynCode = Hash(hashString);

            // Creates a new instance of dynamic code.
            if (dynCode == null)
            {
                string code = @"
            T1 arrOutput = (T1)valInput;
            return arrOutput;";

                dynCode = new DynamicCode();
                dynCode.Compile(new string[] { tin, tout }, "T0 valInput", code);
                dynamicCodeHash.Add(hashString, dynCode);
            }

            // Converts.
            return (TOutput)dynCode.Invoke(input);
        }

        /// <summary>
        /// Converts data of the specified type to another type.
        /// </summary>
        /// <typeparam name="TInput">The type of the input.</typeparam>
        /// <typeparam name="TOutput">The type of the output.</typeparam>
        /// <param name="input">The input data.</param>
        /// <returns>The converted data.</returns>
        public static TOutput[] Convert<TInput, TOutput>(TInput[] input)
        {
            // Gets the corresponding dynamic code.
            string tin = typeof(TInput).ToString();
            string tout = typeof(TOutput).ToString();
            string hashString = "ConvertArray.<" + tin + ">.<" + tout + ">";
            DynamicCode dynCode = Hash(hashString);

            // Creates a new instance of dynamic code.
            if (dynCode == null)
            {
                string code = @" 
            int cnt = arrInput.Length;
            T1[] arrOutput = new T1[cnt];
            for(int i=0; i<cnt; i++)
            {
                arrOutput[i] = (T1)arrInput[i];
            }
            return arrOutput;";

                dynCode = new DynamicCode();
                dynCode.Compile(new string[] { tin, tout }, "T0[] arrInput", code);
                dynamicCodeHash.Add(hashString, dynCode);
            }

            // Converts.
            return (TOutput[])dynCode.Invoke(input);
        }

        /// <summary>
        /// Get the Unit of the specified type.
        /// </summary>
        /// <typeparam name="TOutput">The type of the output.</typeparam>
        /// <returns>The unit value.</returns>
        public static T Unit<T>()
        {
            // Gets the corresponding dynamic code.
            string type = typeof(T).ToString();
            string hashString = "Unit.<" + type + ">";
            DynamicCode dynCode = Hash(hashString);

            // Creates a new instance of dynamic code.
            if (dynCode == null)
            {
                string code = @" 
            T0 unit = (T0)1;
            return unit;";

                dynCode = new DynamicCode();
                dynCode.Compile(new string[] { type }, string.Empty, code);
                dynamicCodeHash.Add(hashString, dynCode);
            }

            // Converts.
            return (T)dynCode.Invoke();
        }
    }
}
